/**
 * Copyright (C) 2009 Olafur Gauti Gudmundsson, Hjortur Stefan Olafsson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.gwt_control.client;

import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;

/**
 * Has no parent controller.
 *
 * @author Olafur Gauti Gudmundsson
 */
public class ApplicationController extends AbstractController {

    protected ApplicationView applicationView;
    protected ApplicationModel applicationModel;
    protected ApplicationEventListener applicationEventListener;
    protected Controller pageController;

    public ApplicationController( ApplicationModel applicationModel, ApplicationEventListener applicationEventListener ) {
        this.applicationEventListener = applicationEventListener;
        applicationView = new ApplicationView(this);
        if ( applicationModel != null ) {
            this.applicationModel = applicationModel;
        } else {
            this.applicationModel = new ApplicationModel();
        }
    }

    @Override
    public void init() {
        initHistoryListener();
        applicationModel.init(this);
    }

    private void initHistoryListener() {
        History.addValueChangeHandler(new ValueChangeHandler<String>() {
            public void onValueChange(ValueChangeEvent<String> event) {
                String historyToken = event.getValue();
                if (historyToken != null && historyToken.trim().length() > 0) {
                    ViewLinkToken token = ViewLinkToken.decode(historyToken);

                    // activate requested controller
                    Controller controller = ApplicationManager.getView(token.getViewId()).open(token);
                    setPageController(controller);
                }
            }
        });
    }

    void onApplicationModelReady( Controller homePageController ) {
        for ( ApplicationLifecycleListener listener : ApplicationManager.getLifecycleListeners() ) {
            listener.onApplicationStartup(applicationModel);
        }

        if ( History.getToken().length() == 0 ) {
            handleNavigation(homePageController);
        } else {
            History.fireCurrentHistoryState();
        }
    }

    private void setPageController(Controller controller) {
        pageController = controller;
        pageController.init(this);
    }

    private void handleNavigation(Controller controller) {
        if ( controller.getViewLinkToken() != null ) {
            // add the browse space ID
            ViewLinkToken token = controller.getViewLinkToken();
            History.newItem(token.encode(), true);
        } else {
            setPageController(controller);
        }
    }

    @Override
    public void handleApplicationEvent(ApplicationEvent event) {
        if ( event instanceof NavigationEvent ) {
            Controller c = ((NavigationEvent)event).getPayload();
            handleNavigation(c);
        } else if ( event instanceof ApplicationModelUpdateEvent ) {
            ApplicationModelUpdateEvent updateEvent = (ApplicationModelUpdateEvent)event;
            applicationModel.setAttribute(updateEvent.getAttributeName(), updateEvent.getPayload());
        } else {
            if ( applicationEventListener != null ) {
                applicationEventListener.onApplicationEvent(event);
            } else {
                Window.alert("UNHANDLED EVENT: " + event.getType());
            }
        }
    }

    @Override
    public void navigateTo(Controller controller) {
        handleApplicationEvent(new NavigationEvent(controller));
    }

    @Override
    protected PageLayout getLayout() {
        return null;
    }

    @Override
    protected Model getModel() {
        return null;
    }

    public ApplicationModel getApplicationModel() {
        return applicationModel;
    }

    public ApplicationView getApplicationView() {
        return applicationView;
    }

    public Controller getCurrentPageController() {
        return pageController;
    }
}
